package com.forum.module.chat.service;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.forum.framework.common.exception.ErrorCode;
import com.forum.framework.common.exception.util.ServiceExceptionUtils;
import com.forum.framework.common.util.object.BeanUtils;
import com.forum.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.forum.framework.security.core.util.SecurityUtils;
import com.forum.module.chat.controller.vo.ChatMessageRespVO;
import com.forum.module.chat.dal.dataobject.chat.ChatMessageDO;
import com.forum.module.chat.dal.mysql.chat.ChatMessageMapper;
import com.forum.module.chat.enums.ChatConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletionException;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.forum.module.chat.enums.ChatConstants.API_URL;
import static com.forum.module.chat.enums.ChatConstants.MODEL_NAME;
import static com.forum.module.system.enums.ErrorCodeConstants.QUESTION_IS_NOT_EMPTY;
import static com.forum.module.system.enums.ErrorCodeConstants.REQUEST_DEEPSEEK_EXCEPTION;

/**
 * 功能:
 * 作者:ouyzh
 * 日期:2025/3/6 20:24
 */
@Service
public class ChatServiceImpl implements ChatService {
    private static final Logger log = LoggerFactory.getLogger(ChatService.class);

    private static final HttpClient CLIENT = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .connectTimeout(Duration.ofSeconds(20))
            .build();

    private final ChatMessageMapper chatMessageMapper;

    public ChatServiceImpl(ChatMessageMapper chatMessageMapper) {
        this.chatMessageMapper = chatMessageMapper;
    }

    @Override
    public String getAnswer(String question) {
        if (StrUtil.isBlank(question)) {
            throw ServiceExceptionUtils.exception(QUESTION_IS_NOT_EMPTY);
        }
        HttpClient client = HttpClient.newHttpClient();
        try {
            // 转义特殊字符
            String escapedQuestion = question
                    .replace("\\", "\\\\")
                    .replace("\"", "\\\"")
                    .replace("\n", "\\n");

            String requestBody = String.format(
                    "{\"model\": \"%s\", \"messages\": [{\"role\": \"user\", \"content\": \"%s\"}], \"temperature\": 0.7}",
                    ChatConstants.MODEL_NAME, escapedQuestion);

            java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
                    .uri(URI.create(ChatConstants.API_URL))
                    .timeout(Duration.ofMinutes(2))
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                    .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() == 200) {
                return parseResponse(response.body());
            } else {
                log.error("请求失败，状态码：{}", response.statusCode() + "响应体：" + response.body());
                throw ServiceExceptionUtils.exception0(response.statusCode(), response.body());
            }
        } catch (Exception e) {
            log.error("请求异常：{}", e.getMessage());
            e.printStackTrace();
            throw ServiceExceptionUtils.exception(REQUEST_DEEPSEEK_EXCEPTION);
        }
    }

    @Override
    public void streamAnswer(String question, SseEmitter emitter) {
        // 简单参数校验
        if (question == null || question.trim().isEmpty()) {
            sendError(emitter, "问题不能为空");
            return;
        }
        Long loginUserId = SecurityUtils.getLoginUserId();

        ChatMessageDO chatMessageDO = new ChatMessageDO();
        // 0 用户 1 机器人
        chatMessageDO.setRole(0);
        chatMessageDO.setUserId(loginUserId);
        chatMessageDO.setContent(question);

        chatMessageMapper.insert(chatMessageDO);

        // 构建请求
        String requestBody = String.format(
                "{\"model\": \"%s\", \"messages\": [{\"role\": \"user\", \"content\": \"%s\"}], \"stream\": true}",
                MODEL_NAME, question.replace("\"", "\\\""));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(API_URL))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        StringBuilder robotAnswerBuilder = new StringBuilder();

        // 异步处理
        HttpClient.newHttpClient()
                .sendAsync(request, HttpResponse.BodyHandlers.ofLines())
                .thenAccept(response -> {
                    // 遍历每一行数据
                    response.body().forEach(line -> {
                        if (line.startsWith("data: ")) {
                            String content = parseContent(line.substring(6).trim());
                            if (content != null) {
                                // 对返回内容进行预处理
                                String processedContent = preProcessContent(content);
                                robotAnswerBuilder.append(processedContent);
                                try {
                                    emitter.send(processedContent); // 实时发送给前端
                                } catch (IOException e) {
                                    emitter.completeWithError(e);
                                }
                            }
                        }
                    });
                })
                .whenComplete((unused, throwable) -> {
                    if (throwable == null) {
                        // 3. 任务结束后，回到主线程插入数据库
                        ChatMessageDO robotMessage = new ChatMessageDO();
                        robotMessage.setRole(1);
                        robotMessage.setUserId(loginUserId); // 这里直接用外面获取的 userId
                        robotMessage.setContent(robotAnswerBuilder.toString());
                        chatMessageMapper.insert(robotMessage);
                    }
                });

    }

    @Override
    public List<ChatMessageDO> history() {
        return chatMessageMapper.selectList(new LambdaQueryWrapperX<ChatMessageDO>()
                .eqIfPresent(ChatMessageDO::getUserId, SecurityUtils.getLoginUserId()));
    }

    /**
     * 预处理返回的内容：
     * 1. 去除所有 <think>...</think> 标签及其内部内容
     * 2. 移除 Markdown 格式标记（例如 "### **"）
     * 3. 对包含 Java 代码的内容，如果检测到典型代码关键字，则包装在 <pre> 标签内，
     *    以保证代码格式显示整齐、单词之间有足够空隙。
     */
    private String preProcessContent(String content) {
        if (content == null || content.isEmpty()) {
            return "";
        }

        // 阶段0：处理Unicode转义形式（关键新增）
        String processed = content
                .replace("\\u003cthink\\u003e", "")  // 处理Unicode转义的开始标签
                .replace("\\u003c/think\\u003e", ""); // 处理Unicode转义的结束标签

        // 阶段1：处理所有可能的标签形式（增强正则）
        processed = processed
                // 处理常规标签形式（含属性、大小写、跨行）
                .replaceAll("(?si)<\\s*think\\b[^>]*>.*?</\\s*think\\s*>", "")
                // 处理HTML实体编码形式
                .replaceAll("(?i)&lt;think&gt;.*?&lt;/think&gt;", "")
                // 处理残缺标签（如未闭合）
                .replaceAll("(?i)<\\s*/?think\\b[^>]*>", "");

        // 阶段2：深度清理残留（防御性处理）
        return processed
                .replace("think>", "")  // 处理异常残留
                .replace("<think", "")  // 处理异常开始
                .trim();
    }

    // 简单解析方法
    private String parseContent(String jsonLine) {
        try {
            // 直接通过字符串操作提取content
            int start = jsonLine.indexOf("\"content\":\"") + 11;
            int end = jsonLine.indexOf("\"", start);
            return jsonLine.substring(start, end)
                    .replace("\\n", "\n")
                    .replace("\\\"", "\"");
        } catch (Exception e) {
            return null;
        }
    }

    private void sendError(SseEmitter emitter, String message) {
        try {
            emitter.send(SseEmitter.event().data(message));
            emitter.complete();
        } catch (IOException e) {
            emitter.completeWithError(e);
        }
    }

    private String parseSSELine(String line) {
        if (!line.startsWith("data: ")) return null;

        String json = line.substring(6).trim();
        if (json.equals("[DONE]")) return null;

        try {
            JsonNode node = new ObjectMapper().readTree(json);
            if (node.has("choices")) {
                return node.get("choices").get(0)
                        .get("delta").get("content").asText();
            }
        } catch (JsonProcessingException e) {
            log.warn("SSE数据解析失败: {}", json);
        }
        return null;
    }

    private static String buildRequestBody(String question) {
        return String.format(
                "{\"model\": \"%s\", \"messages\": [{\"role\": \"user\", \"content\": \"%s\"}], \"stream\": true}",
                MODEL_NAME,
                question.replace("\\", "\\\\")
                        .replace("\"", "\\\"")
                        .replace("\n", "\\n")
                        .replace("\r", "\\r")
        );
    }

    private static HttpRequest createHttpRequest(String body) {
        return HttpRequest.newBuilder()
                .uri(URI.create(API_URL))
                .timeout(Duration.ofMinutes(2))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .build();
    }

    private static String processSSELine(String line) {
        // 处理SSE数据行
        if (line.startsWith("data: ")) {
            String jsonData = line.substring(6).trim();
            return parseSSEData(jsonData);
        }
        return "";
    }

    private static String parseSSEData(String jsonData) {
        try {
            // 检查流结束标志
            if (jsonData.contains("\"done\": true")) {
                return "";
            }

            // 定位content字段
            int contentStart = jsonData.indexOf("\"content\":\"") + 11;
            if (contentStart < 11) return "";

            int contentEnd = jsonData.indexOf('"', contentStart);
            if (contentEnd == -1) return "";

            // 提取并处理转义字符
            return jsonData.substring(contentStart, contentEnd)
                    .replace("\\n", "\n")
                    .replace("\\\"", "\"")
                    .replace("\\\\", "\\")
                    .replace("\\t", "\t");
        } catch (Exception e) {
            System.err.println("\nJSON解析错误：" + e.getMessage());
            return "";
        }
    }

    private static void handleErrorResponse(HttpResponse<?> response) {
        System.err.println("\n请求失败，状态码：" + response.statusCode());
        System.err.println("可能原因：");

        switch (response.statusCode()) {
            case 400:
                System.err.println("- 请求格式错误");
                System.err.println("- 模型不可用");
                break;
            case 404:
                System.err.println("- API地址不正确");
                System.err.println("- 服务未启动");
                break;
            case 500:
                System.err.println("- 服务器内部错误");
                break;
            default:
                System.err.println("- 未知错误");
        }

        System.err.println("\n完整响应头：\n" + response.headers());
    }

    private String parseResponse(String jsonResponse) {
        // 简易JSON解析
        try {
            int start = jsonResponse.indexOf("\"content\":\"") + 11;
            int end = jsonResponse.indexOf("\"", start);
            return jsonResponse.substring(start, end)
                    .replace("\\n", "\n")
                    .replace("\\\"", "\"");
        } catch (Exception e) {
            return "解析响应失败：" + e.getMessage() + "\n原始响应：" + jsonResponse;
        }
    }

    private String formatAnswer(String answer) {
        // 简单格式化换行
        return answer.replace("。", "。\n");
    }

    private String escapeJson(String text) {
        return text.replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\n", "\\n");
    }
}
